package com.nwpu.bigdata.service.impl;

import com.nwpu.bigdata.dao.mapper.*;
import com.nwpu.bigdata.dto.BackendResult;
import com.nwpu.bigdata.model.*;
import com.nwpu.bigdata.service.FaultDetectionService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;

/**
 * @author carlin
 * @date 2018/7/30 0030 11:03
 */
@Service
public class FaultDetectionServiceImpl implements FaultDetectionService {

    private static final Logger logger = LoggerFactory.getLogger(FaultDetectionServiceImpl.class);
    private static final Long PAGE_SIZE = 15L;

    @Autowired
    EventMapper eventMapper;

    @Autowired
    FaultMapper faultMapper;

    @Autowired
    MediaMapper mediaMapper;

    @Autowired
    UserMapper userMapper;


    /**
     * 将检测到的故障插入故障表中
     *
     * @param fault 需要插入的故障
     * @return 故障插入成功的数量
     */
    private int insertFault(Fault fault) {
        return faultMapper.insert(fault);
    }

    @Override
    public void faultDetection(Rule rule, long interval) {
        Date currentTime = new Date();
        Date sourceStartTime = new Date(System.currentTimeMillis() - interval);
        Long count = eventMapper.countbysourcestarttime(rule.getId(), sourceStartTime, currentTime);
        if (count >= rule.getFaultTimes()) {
            Fault fault = new Fault();
            fault.setRuleId(rule.getId());
            fault.setUserId(rule.getUserId());
            fault.setMediaTypeId(rule.getMediaTypeId());
            String sendTo = userMapper.selectByMediaType(rule.getUserId(),
                    mediaMapper.selectByPrimaryKey(rule.getMediaTypeId()).getMediaName());
            fault.setSendTo(sendTo);
            fault.setSubject(rule.getRuleName() + ": " + rule.getDescription());
            fault.setMessage(fault.getSubject());
            fault.setIsSent((byte) 0);
            fault.setIsAcked((byte) 0);
            fault.setGmtCreate(new Date());
            fault.setGmtModified(new Date());
            int num = insertFault(fault);
            if (num < 1) {
                logger.error("the insert mysql fault number is 0");
            } else {
                logger.info("the insert mysql fault number is {}", num);
            }
        } else {
            logger.info("the insert mysql fault number is 0");
        }
    }

    @Override
    public BackendResult<List<FaultExtend>> listFaults(User user, Long page) {
        Long low = (page - 1) * PAGE_SIZE;
        List<FaultExtend> faults = faultMapper.selectFaultByPage(user.getId(), low, PAGE_SIZE);
        if (faults == null) {
            logger.error("the page {} error, no full fault info !", page);
            return new BackendResult<>(false, "the page error, no full fault info !");
        } else {
            logger.info("the page {} has {} faults info !", faults.size());
            return new BackendResult<List<FaultExtend>>(true, faults);
        }
    }

    @Override
    public long countFault(User user) {
        FaultExample faultExample = new FaultExample();
        FaultExample.Criteria criteria = faultExample.createCriteria();
        criteria.andUserIdEqualTo(user.getId());
        return faultMapper.countByExample(faultExample);
    }

    @Override
    public Long deleleFaultIsAck() {
        FaultExample faultExample = new FaultExample();
        FaultExample.Criteria criteria = faultExample.createCriteria();
        criteria.andIsAckedEqualTo((byte) 1);
        return faultMapper.deleteByExample(faultExample);
    }

    @Override
    public BackendResult<Integer> updateFaultStatusAck(Long id) {
        Fault fault = new Fault();
        fault.setIsAcked((byte) 1);
        fault.setGmtModified(new Date());
        FaultExample faultExample = new FaultExample();
        FaultExample.Criteria criteria = faultExample.createCriteria();
        criteria.andIdEqualTo(id);
        int effectNum = faultMapper.updateByExampleSelective(fault, faultExample);
        if(effectNum > 0) {
            logger.info("update Fault id {} ack Status !", id);
            return new BackendResult<>(true, effectNum);
        }else {
            logger.info("no update Fault id {} ack Status!", id);
            return new BackendResult<>(false, "Fault id {} is already ack Status!");
        }
    }

    @Override
    public BackendResult<FaultExtend> selectFaultById(Long id) {
        FaultExtend faultExtend = faultMapper.selectFaultById(id);
        if(faultExtend != null) {
            return new BackendResult<>(true, faultExtend);
        }else {
            logger.error("The fault id {} error, no data in db!", id);
            return new BackendResult<>(false, "The id error, no data in db!");
        }
    }

    @Override
    public BackendResult<List<Fault>> selectFaultByIsSent() {
        FaultExample faultExample = new FaultExample();
        FaultExample.Criteria criteria = faultExample.createCriteria();
        criteria.andIsSentEqualTo((byte) 0);
        List<Fault> faults = faultMapper.selectByExample(faultExample);
        if(faults != null && faults.size() != 0) {
            return new BackendResult<>(true, faults);
        }else {
            return new BackendResult<>(false, "fault info already all are sent!");
        }
    }

    @Override
    public BackendResult<Integer> updateFaultStatusSent(Long id) {
        FaultExample faultExample = new FaultExample();
        FaultExample.Criteria criteria = faultExample.createCriteria();
        criteria.andIdEqualTo(id);
        Fault fault = new Fault();
        fault.setIsAcked((byte) 1);
        fault.setGmtModified(new Date());
        int effectNum = faultMapper.updateByExampleSelective(fault, faultExample);

        if(effectNum > 0) {
            logger.info("update Fault id {} sent status !", id);
            return new BackendResult<>(true, effectNum);
        }else {
            logger.info("no update Fault id {} sent Status!", id);
            return new BackendResult<>(false, "Fault id {} is already sent Status!");
        }
    }

}
